let electron = require('electron');
let fs = require('fs');
let path = require('path');
let configuration = require('../configuration');
let Component = require('./Component');
let ipc = electron.ipcRenderer;
let ComponentContainer = require('./ComponentContainer');

const eventPath = path.join(__dirname, 'ipc-events/');
const events = fs.readdirSync(eventPath);
const innerEventPath = path.join(__dirname, 'inner-events/');
const innerEvents = fs.readdirSync(innerEventPath);

const game = module.exports;
let canvas = null;
let componentContainer = new ComponentContainer();
let eventHandlers = {};
let devMode = false;
let descriptionRecorder = null;
let eventListeners = new Set([]);

game.init = function (_canvas) {
    configuration.init();
    devMode = configuration.get('dev.enabled', false);
    canvas = _canvas;
    componentContainer.init({
        game: game,
        canvas: _canvas,
        baseX: 0,
        baseY: 0
    });
    for (let event of events) {
        event = event.substring(0, event.length - '.js'.length);
        let e = require('./ipc-events/' + event);
        e.init({
            ipc: ipc,
            canvas: canvas,
            game: game
        });
        ipc.on(event, e.listen);
    }
    for (let event of innerEvents) {
        event = event.substring(0, event.length - '.js'.length);
        let e = require('./inner-events/' + event);
        e.init({
            ipc: ipc,
            canvas: canvas,
            game: game
        });
        eventHandlers[event] = e;
    }
};

let frames = 0;
let fps = 0;
let lastFpsRecord = -1;

game.draw = function (canvas) {
    frames += 1;
    let now = Date.now();
    if ((now - lastFpsRecord) > 500) {
        let deltaT = now - lastFpsRecord;
        fps = parseInt(frames / deltaT * 1000);
        lastFpsRecord = now;
        frames = 0;
    }
    componentContainer.draw(canvas);
    let ctx = canvas.getContext('2d');
    __showDescription(ctx);
    if (devMode) {
        ctx.save();
        ctx.textBaseline = 'top';
        ctx.textAlign = 'left';
        ctx.font = '40px Helvetica Helvetica';
        ctx.fillText('fps: ' + fps, 0, 0);
        ctx.restore();
    }
};

game.addComponent = function (comp, id, zIndex) {
    componentContainer.addComponent(comp, id, zIndex);
};

game.removeAllComponents = function () {
    componentContainer.removeAllComponents();
};

game.mouseMove = function (x, y) {
    componentContainer.mouseMove(x, y);
};

game.mouseDown = function (x, y) {
    componentContainer.mouseDown(x, y);
};

game.mouseUp = function () {
    componentContainer.mouseUp();
};

game.componentBroadcast = function (route, sender, msg) {
    componentContainer.componentBroadcast(route, sender, msg);
    route = 'on' + route.substring(0, 1).toUpperCase() + route.substring(1);
    for (let lsn of eventListeners) {
        if (lsn[route]) {
            lsn[route](sender, msg);
        }
    }
};

game.broadcast = function (route, sender, msg) {
    if (eventHandlers[route]) {
        eventHandlers[route].listen(sender, msg);
    }
    game.componentBroadcast(route, sender, msg);
};

game.addEventListener = function (lsn) {
    eventListeners.add(lsn);
};

game.removeEventListener = function (lsn) {
    eventListeners.delete(lsn);
};

game.showErrorMsg = function (text, timeout) {
    let ErrorMsg = require('./components/sys/errorMsg');
    componentContainer.addComponent(new ErrorMsg(text, timeout), null, 100);
};

function getRealPosition(container, x, y) {
    while (container) {
        x += container.baseX;
        y += container.baseY;
        container = container.parentComponentContainer;
    }
    return {x: x, y: y};
}

game.showDescription = function (id, container, x, y, height, descFunc) {
    let pos = getRealPosition(container, x, y);
    descriptionRecorder = {
        id: id,
        x: pos.x,
        y: pos.y,
        height: height,
        func: descFunc
    };
};

game.hideDescription = function (id) {
    if (descriptionRecorder && descriptionRecorder.id === id) {
        descriptionRecorder = null;
    }
};

function __showDescription(ctx) {
    let description = descriptionRecorder;
    if (!description) return;

    let x = description.x;
    let y = description.y;

    let funcToDraw = description.func;

    let windowWidth = configuration.get('window.width');
    let windowHeight = configuration.get('window.height');
    let width = configuration.get('components.desc.width');
    let height = description.height;
    let descX = (x + width > windowWidth) ? x - width : x;
    let descY = (y + height > windowHeight) ? y - height : y;

    ctx.save();
    ctx.translate(descX, descY);
    ctx.save();
    ctx.beginPath();
    ctx.rect(0, 0, width, height);
    ctx.stroke();
    ctx.fillStyle = 'rgba(0,0,0,0.6)';
    ctx.fill();
    ctx.restore();
    ctx.beginPath();
    funcToDraw(ctx, width);
    ctx.restore();
}
